package com.atguigu.gmall.product.service.impl;

import com.atguigu.gmall.common.cache.BloomName;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.feign.search.SkuEsFeignClient;
import com.atguigu.gmall.model.list.Goods;
import com.atguigu.gmall.model.list.SearchAttr;
import com.atguigu.gmall.model.product.*;
import com.atguigu.gmall.product.mapper.*;
import com.atguigu.gmall.product.service.SkuInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.redisson.api.RBloomFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;


@Service
public class SkuInfoServiceImpl extends ServiceImpl<SkuInfoMapper, SkuInfo> implements SkuInfoService {


    @Autowired
    SkuInfoMapper skuInfoMapper;

    @Autowired
    SkuImageMapper skuImageMapper;

    @Autowired
    SkuAttrValueMapper skuAttrValueMapper;

    @Autowired
    SkuSaleAttrValueMapper skuSaleAttrValueMapper;

    @Autowired
    BaseTrademarkMapper baseTrademarkMapper;


    @Autowired
    BaseCategory3Mapper baseCategory3Mapper;
    @Autowired
    BaseCategory2Mapper baseCategory2Mapper;
    @Autowired
    BaseCategory1Mapper baseCategory1Mapper;

    @Autowired
    ThreadPoolExecutor executor;


//    @Autowired
//    RedissonClient redissonClient;

    @Qualifier(BloomName.SKU)
    @Autowired
    RBloomFilter<Object> skufilter;


    @Autowired
    SkuEsFeignClient skuEsFeignClient;


    /**
     * *  SPU：录入SPU，平台属性暂时没有参与，录入SKU的时候会有展示.
     * *  SKU的录入：
     * *      1、sku的详情：sku_info
     * *      2、sku的图片：sku_image
     * *         内容来自spu_image的一部分
     * *      3、sku的属性
     * *          3.1）、sku平台属性 : 来源于 base_attr_info  base_attr_value  sku_info
     * *                 被记录在 sku_attr_value（他是base_attr_info  base_attr_value  sku_info的中间表）   价格： 0-499
     * *          3.2）、sku销售属性 ：来源于 spu_sale_attr_value
     * *                 被记录在 sku_sale_attr_value （他是 sku_info spu_sale_attr_value的中间表）
     */
    //保存SKU信息
    @Transactional
    @Override
    public boolean bigSaveSkuInfo(SkuInfo skuInfo) {


        //1、保存skuinfo基础信息，数据校验
//        if(skuInfo.getPrice() == null){
//            return false;
//        }
        int insert = skuInfoMapper.insert(skuInfo);

        Long skuId = skuInfo.getId();
        //只要操作了数据库，赶紧告诉布隆，我插入了数据


        //2、保存sku图片信息   sku_image
        List<SkuImage> skuImageList = skuInfo.getSkuImageList();
        if (!CollectionUtils.isEmpty(skuImageList)) {
            for (SkuImage skuImage : skuImageList) {
                skuImage.setSkuId(skuId);
                skuImageMapper.insert(skuImage);
            }
        }

        //3、保存sku的平台属性对应的所有值 sku_attr_value
        //attr_id  value_id  sku_id
        // 1         2        skuId
        List<SkuAttrValue> skuAttrValueList = skuInfo.getSkuAttrValueList();
        if (!CollectionUtils.isEmpty(skuAttrValueList)) {
            for (SkuAttrValue skuAttrValue : skuAttrValueList) {
                skuAttrValue.setSkuId(skuId);
                skuAttrValueMapper.insert(skuAttrValue);
            }
        }


        //4、保存sku的销售属性以及值信息 sku_sale_attr_value
        // sku_id   spu_id   sale_attr_value_id(来源于spu_sale_attr_value的id )
        //  200       2         123
        /**
         * "saleAttrValueId":"123", spu_sale_attr_value 的id
         * "baseSaleAttrId":"1",   base_sale_attr 的 id
         */
        List<SkuSaleAttrValue> skuSaleAttrValueList = skuInfo.getSkuSaleAttrValueList();
        if (!CollectionUtils.isEmpty(skuSaleAttrValueList)) {
            for (SkuSaleAttrValue attrValue : skuSaleAttrValueList) {
                attrValue.setSpuId(skuInfo.getSpuId());
                attrValue.setSkuId(skuId);
                skuSaleAttrValueMapper.insert(attrValue);
            }
        }

        //假设改完了数据
//        skuId
//        redis.set("sku:info:"+skuId,skuInfoJson)  //双写
//        redis.delete("sku:info:"+skuId)  //失效
//                //失效模式可能导致缓存击穿。 100万请求查skuId，正好改了，
//                使用了失效模式。导致缓存中没有要查数据库。（如果没有加锁解决问题），就会缓存击穿

        //TODO 让bloomfilter保存一下
        // 缓存按照key:  每保存的商品id，布隆要同步
        String cacheKey = RedisConst.SKUKEY_PREFIX + skuId + RedisConst.SKUKEY_SUFFIX;
        skufilter.add(cacheKey);
        return true;
    }

    /**
     * 事务 + 远程调用；
     * 本地事务：（长事务）
     *    RPC ......
     *  1）、事务里面不要写远程调用，分布式系统不可避免的时候，
     *          远程做成异步编排，不阻塞数据库事务
     *  2）、分布式事务:
     * @param skuId
     * @return
     */
    @Transactional
    @Override
    public boolean onSale(Long skuId) {
        //1、上架修改数据库
        skuInfoMapper.updateSkuSaleStatus(skuId,1);


        /**
         * 以下的所有数据都是全异步
         */
        Goods goods = new Goods();
        //TODO 2、把商品信息同步到搜索引擎，把SKU所有详情全部查出，封装到 goods中
        CompletableFuture<SkuInfo> skuInfoFuture = CompletableFuture.supplyAsync(() -> {
            //1、封装基本信息
            SkuInfo skuInfo = skuInfoMapper.selectById(skuId);
            goods.setId(skuInfo.getId());
            goods.setDefaultImg(skuInfo.getSkuDefaultImg());
            goods.setTitle(skuInfo.getSkuName());
            return skuInfo;
        },executor);

        CompletableFuture<Void> priceFuture = CompletableFuture.runAsync(() -> {
            //2、封装价格
            BigDecimal skuPrice = skuInfoMapper.getSkuPrice(skuId);
            goods.setPrice(skuPrice);
        },executor);

//        goods.setCreateTime(new Date());  //不在这里准备时间，以es的处理为准
        CompletableFuture<Void> baseTrademarkFuture = CompletableFuture.runAsync(() -> {
            //3、封装品牌信息
            BaseTrademark baseTrademark = baseTrademarkMapper.getBaseTradeBySkuId(skuId);
            goods.setTmId(baseTrademark.getId());
            goods.setTmName(baseTrademark.getTmName());
            goods.setTmLogoUrl(baseTrademark.getLogoUrl());
        }, executor);


        CompletableFuture<Void> categoryFuture = skuInfoFuture.thenAcceptAsync((skuInfo) -> {
            //4、封装分类
            BaseCategory3 baseCategory3 = baseCategory3Mapper.selectById(skuInfo.getCategory3Id());
            goods.setCategory3Id(baseCategory3.getId());
            goods.setCategory3Name(baseCategory3.getName());
            BaseCategory2 baseCategory2 = baseCategory2Mapper.selectById(baseCategory3.getCategory2Id());
            goods.setCategory2Id(baseCategory2.getId());
            goods.setCategory2Name(baseCategory2.getName());
            BaseCategory1 baseCategory1 = baseCategory1Mapper.selectById(baseCategory2.getCategory1Id());
            goods.setCategory1Id(baseCategory1.getId());
            goods.setCategory1Name(baseCategory1.getName());
        },executor);

        CompletableFuture<Void> searchAttrsFuture = CompletableFuture.runAsync(() -> {
            //6、当前SKU对应的所有平台属性以及值
            List<SearchAttr> searchAttrs = skuAttrValueMapper.getBaseAttrAndValuesBySkuId(skuId);
            goods.setAttrs(searchAttrs);
        });


        //5、 热度分。每进入商品详情页一次就+1热度
        CompletableFuture<Void> allFuture = CompletableFuture
                .allOf(skuInfoFuture, priceFuture, baseTrademarkFuture, categoryFuture, searchAttrsFuture);

        allFuture.whenCompleteAsync((res,exc)->{
            //远程调用检索服务，保存到es
            skuEsFeignClient.saveSkuToEs(goods);
        },executor);

        return true;
    }

    //503  Service Unavailable
    @Override
    public boolean cancelSale(Long skuId) {
        //1、下架修改数据
        skuInfoMapper.updateSkuSaleStatus(skuId,0);

        CompletableFuture.runAsync(()->{
            //TODO 2、把商品信息从搜索引擎移除
            skuEsFeignClient.deleteSkuFromEs(skuId);
        },executor);

        return true;
    }

    @Override
    public List<Long> getAllId() {


        return skuInfoMapper.getAllIds();
    }
}
